﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PixentrationEngine;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Threading;
using System.IO;

namespace PixentrationEngineTest
{
 
    /// <summary>
    /// Test program for Pixentration game engine.
    /// Results log out to a file located at c:\program data\pixentration\enginetests
    /// </summary>
    class Program
    {
        static int BOARD_SIZE = 4;
        const int IMAGE_HEIGHT = 100;
        const int IMAGE_WIDTH = 100;
        const int GAME_TIME = 15;

        static string FILE_PATH;
        static string FILE_NAME;
        static string TARGET;
        static DirectoryInfo DI;
        static StreamWriter sw;

        static PixentrationGame pix;

        static void Main(string[] args)
        {
            CreateLogFile();
            sw = new StreamWriter(TARGET);

            pix = new PixentrationGame();
            PixGameSettings gs = new PixGameSettings();
            Size sz = new Size();

            // Set up event listeners
            GameStateHandler state = new GameStateHandler(pix, sw);
            TimingHandler time = new TimingHandler(pix, sw);
            ScoreHandler score = new ScoreHandler(pix, sw);

            sz.Height = IMAGE_HEIGHT;
            sz.Width = IMAGE_WIDTH;
            gs.ImageSize = sz; 
            gs.GameTime = GAME_TIME;
            gs.URL = null;

            // Test E18
            gs.BoardSize = 37;

            try
            {
                pix.Initialize(gs);
            }
            catch (Exception e)
            {
                sw.WriteLine("E18 passed. Caught exception for BoardSize = 37. Exception: " + e.Message);
            }

            gs.BoardSize = 5;

            // Test E19
            try
            {
                pix.Initialize(gs);
            }
            catch (Exception e)
            {
                sw.WriteLine("E19 passed. Caught exception for BoardSize = 5. Exception: " + e.Message);
            }
            gs.BoardSize = 2;
            pix.Initialize(gs);
            TestMatchedPairs();

            // Attempt to get back image.
            Image backImg = pix.BackImage;
            if (backImg.Tag.ToString().Contains("Back.jpg"))
            {
                sw.WriteLine("Back image retrieved.");
            }
            backImg.Save("C:\\BackImageTest.jpg");

            gs.BoardSize = BOARD_SIZE;

            pix.Initialize(gs);

            ScorecardTest();

            Boolean b = pix.SetHighScoreName("Jim");


            // E13: try to set high score in invalid state
            if (b == true)
                sw.WriteLine("E13: FAILED");
            else
                sw.WriteLine("E13: passed");

            Console.WriteLine("Wait for end of tests message to close window.");

            ImageTests();           
             
            pix.Start();

            // E16, E17
            TestInvalidIndexes();

            sw.WriteLine("Running 5 seconds...");
            Thread.Sleep(5000);

            sw.WriteLine("Pausing...");
            pix.Pause();

            Thread.Sleep(2000);

            sw.WriteLine("Restarting...");
            pix.Start();


            while (pix.CurrentState != PixGameState.Ended &&
                pix.CurrentState != PixGameState.EndedWithHighScore)
            {
                // don't put code here! Running down timer.
            }

            RestartTest();

            // Start another game
            BOARD_SIZE = 36;
            gs.BoardSize = 36;
            pix.Initialize(gs);

            pix.Start();

            // Test all combinations
            TestMatches();

            while (pix.CurrentState != PixGameState.Ended &&
                pix.CurrentState != PixGameState.EndedWithHighScore)
            {
                // don't put code here! Running down timer.
            }

            BOARD_SIZE = 36;
            gs.BoardSize = 36;
            gs.URL = "C:\\Users\\Public\\Pictures\\Sample Pictures";
            pix.Initialize(gs);

            pix.Start();

            TestMatchedPairs();

            foreach (Image img in pix.GetImages())
            {
                img.Save("c:\\" + img.Tag.ToString());
            }


            Console.WriteLine("END OF TESTS");

            sw.WriteLine("END OF TESTS");
 

            Console.ReadLine();

            sw.Flush();
            sw.Close();
        }

        static void TestInvalidIndexes()
        {
            Boolean test1 = false;
            Boolean test2 = false;

            try
            {
                pix.TestMatch(1, 1);
            }
            catch (Exception e)
            {
                sw.WriteLine(e.Message);
                sw.WriteLine("E16 (identical indexes for match): Passed");
                test1 = true;
            }

            try
            {
                pix.TestMatch(1, -1);
            }
            catch (Exception e)
            {
                sw.WriteLine(e.Message);
                sw.WriteLine("E17 (index less than zero for match): Passed");
                test2 = true;
            }

            if (test1 == false)
            {
                sw.WriteLine("E16 (identical indexes for match): FAILED");
            }

            if (test2 == false)
            {
                sw.WriteLine("E17 (index less than zero for match): FAILED");
            }

            sw.Flush();

        }

        /// <summary>
        /// E6  test scorecard retrieval
        /// </summary>
        static void ScorecardTest()
        {
            IList<ScoreEntry> scores = pix.GetScores();

            sw.WriteLine("Scorecard file: ");
            foreach (ScoreEntry se in scores)
            {
                sw.WriteLine(se.Name + " " + se.Score + " " + se.Time);
            }
        }

        /// <summary>
        /// Test E23
        /// </summary>
        static void RestartTest()
        {
            // E23
            // Try to restart game.
            sw.WriteLine("Attempting to restart stopped game.");
            pix.Start();
            Thread.Sleep(2000);
            if (pix.CurrentState == PixGameState.Running)
            {
                sw.WriteLine("E23 (restart after stop): FAILED!");
            }
            else
            {
                sw.WriteLine("E23 (restart after stop): Passed.");
            }

            sw.Flush();
        }

        /// <summary>
        /// Helper function to create output log file for test results.
        /// </summary>
        static void CreateLogFile()
        {
            FILE_PATH = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
               + "\\Pixentration\\EngineTests";

            DI = Directory.CreateDirectory(FILE_PATH);

            FILE_NAME = "EngineTests.txt";

            TARGET = FILE_PATH + "\\" + FILE_NAME;

            if (File.Exists(TARGET))
                File.Delete(TARGET);

            FileStream fs = File.Create(TARGET);
            fs.Close();

            // Delete any existing high scores file
            File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
               + "\\Pixentration\\highscores.txt");

        }

        /// <summary>
        /// E7, E8, E9, E10, E11, E15, E15
        /// Exhaustively test matches
        /// Causes game to end with high score.
        /// </summary>
        static void TestMatches()
        {
            for(int i = 0; i < BOARD_SIZE; i++)
            {
                for (int j = 0; j < BOARD_SIZE; j++)
                {
                    if (pix.CurrentState == PixGameState.EndedWithHighScore ||
                            pix.CurrentState == PixGameState.Ended)
                    {
                        break;
                    }

                    if (i != j)
                    {
                        if (pix.CurrentState == PixGameState.EndedWithHighScore ||
                            pix.CurrentState == PixGameState.Ended)
                        {
                            break;
                        }

                        Boolean ret = pix.TestMatch(i, j);
                        sw.WriteLine("Match test: " + i + ", " + j + ": " + ret);
                        sw.Flush();
                    }
                }
            }
        }

        /// <summary>
        /// Engine must return a list of stock images on demand
        /// Test cases:
        /// E1
        /// E2
        /// </summary>
        /// <returns></returns>
        static void ImageTests()
        {
           
            List<Image> imgs;
            int count = 0;

            imgs = pix.GetImages();

            // Log image info
            foreach (Image img in imgs)
            {
                count++;
                sw.WriteLine("Image " + count + " Height: " + img.Height + " Width: " + img.Width);
                if (img.Height == IMAGE_HEIGHT && img.Width == IMAGE_WIDTH)
                {
                    sw.WriteLine("E2 Image size passed");
                }
                else
                {
                    sw.WriteLine("E2 IMAGE SIZE FAILED!");
                }

                string fname = img.Tag.ToString().Remove(0, 36);
                img.Save("C:\\" + fname);

            }

            // Test for correct board size/image count
            if (count == BOARD_SIZE)
            {
                sw.WriteLine("E1 Image count passed: " + count);
            }
            else
            {
                sw.WriteLine("E1 IMAGE COUNT FAILED! " + count + " (should have been) " + BOARD_SIZE);
            }

            sw.Flush();
        }

        /// <summary>
        /// Test E3
        /// </summary>
        static void TestMatchedPairs()
        {
            IList<Image> imgs = pix.GetImages();

            if (imgs[0].Tag == imgs[1].Tag)
            {
                sw.WriteLine("E3 passed. Image 1: " + imgs[0].Tag + " Image 2: " + imgs[1].Tag);
            }
            else
            {
                sw.WriteLine("E3 failed. Image 1: " + imgs[0].Tag + " Image 2: " + imgs[1].Tag);
            }

            sw.Flush();
        }



    }
}
